package com.zjw.zy.heart.service.impl;

import com.zjw.zy.heart.bean.weather.WeatherDaysResult;
import com.zjw.zy.heart.bean.weather.WeatherHoursResult;
import com.zjw.zy.heart.service.IWeatherService;
import com.zjw.zy.heart.service.http.HttpService;
import com.zjw.zy.heart.utils.LogUtils;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import jakarta.annotation.Nullable;
import lombok.NonNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@Service
public class WeatherServiceImpl implements IWeatherService {

    private static final String TAG = "WeatherServiceImpl";
    private HttpService httpService;

    private final Map<Long, Boolean> updateWeatherChecker = new ConcurrentHashMap<>();
    private final Map<Long, WeatherDaysResult> cacheWeatherDaysResultHolder = new ConcurrentHashMap<>();
    private final Map<Long, WeatherHoursResult> cacheWeatherHoursResultHolder = new ConcurrentHashMap<>();
    private Disposable timeScheduler;

    public WeatherServiceImpl() {
        timeScheduler = Observable.interval(0L, 1L, TimeUnit.HOURS).subscribeOn(Schedulers.io()).subscribe(aLong -> {
            //标记
            updateWeatherChecker.replaceAll((c, v) -> true);
        });
    }

    @Override
    public WeatherDaysResult getDayWeather(int days, long areaCode) {
        awaitUpdateIfNeed(areaCode);
        return cacheWeatherDaysResultHolder.get(areaCode);
    }

    @Override
    public WeatherHoursResult getHourWeather(int hour, long areaCode) {
        awaitUpdateIfNeed(areaCode);
        return cacheWeatherHoursResultHolder.get(areaCode);
    }


    @NonNull
    private CountDownLatch updateWeatherInner(@Nullable long areaCode) {
        LogUtils.d(TAG, "start updateWeather areaCode:" + areaCode);
        CountDownLatch countDownLatch = new CountDownLatch(2);
        httpService.requestDaysWeather(obj -> {
            cacheWeatherDaysResultHolder.put(areaCode, obj);
            countDownLatch.countDown();
            LogUtils.d(TAG, "requestDaysWeather end");
        }, 15, areaCode);

        httpService.requestHourlyWeather(obj -> {
            cacheWeatherHoursResultHolder.put(areaCode, obj);
            countDownLatch.countDown();
            LogUtils.d(TAG, "requestHourlyWeather end");
        }, 24, areaCode);

        return countDownLatch;
    }

    public void awaitUpdateIfNeed(long areaCode) {

        boolean needUpdate = updateWeatherChecker.computeIfAbsent(areaCode, key -> true);

        if (!needUpdate) {
            LogUtils.d(TAG, "awaitUpdateIfNeed update:false");
            return;
        }
        LogUtils.d(TAG, "start update weather");

        CountDownLatch countDownLatch = updateWeatherInner(areaCode);
        try {
            boolean await = countDownLatch.await(5000L, TimeUnit.MILLISECONDS);
            updateWeatherChecker.put(areaCode, false);
        } catch (InterruptedException e) {
            LogUtils.e(TAG, "awaitUpdate", e);
        }
    }


    @Autowired
    public void setHttpService(HttpService httpService) {
        this.httpService = httpService;
    }
}
